<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
	<meta name="description" content="">
	<meta name="author" content="">
	<!--<link rel="icon" href="../../favicon.ico">-->

	<title>Filter dropdown - FooTable</title>

	<!-- Bootstrap core CSS -->
	<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
	<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet">

	<!-- Prism -->
	<link href="../../css/prism.css" rel="stylesheet">

	<!-- FooTable Bootstrap CSS -->
	<link href="../../../compiled/footable.bootstrap.min.css" rel="stylesheet">

	<!-- Custom styles for this template -->
	<link href="../../css/docs.css" rel="stylesheet">

	<script src="../../js/demo-rows.js"></script>
	<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
	<!--[if lt IE 9]>
	<script src="//oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
	<script src="//oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
	<![endif]-->
</head>

<body class="docs">

<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
	<div class="container">
		<div class="navbar-header">
			<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
				<span class="sr-only">Toggle navigation</span>
				<span class="icon-bar"></span>
				<span class="icon-bar"></span>
				<span class="icon-bar"></span>
			</button>
			<a href="../../../index.html" class="navbar-brand">FooTable</a>
		</div>
		<div id="navbar" class="navbar-collapse collapse">
			<ul class="nav navbar-nav">
				<li><a href="../../getting-started.html">Getting started</a></li>
				<li class="dropdown">
					<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Components <span class="caret"></span></a>
					<ul class="dropdown-menu">
						<li><a href="../../components/editing.html">Editing</a></li>
						<li><a href="../../components/filtering.html">Filtering</a></li>
						<li><a href="../../components/paging.html">Paging</a></li>
						<li><a href="../../components/sorting.html">Sorting</a></li>
						<li><a href="../../components/state.html">State</a></li>
					</ul>
				</li>
			</ul>
			<ul class="nav navbar-nav navbar-right">
				<li><a href="../../jsdocs/index.html" target="_blank">JSDocs</a></li>
				<li><a href="https://github.com/fooplugins/FooTable" target="_blank">GitHub</a></li>
			</ul>
		</div><!--/.nav-collapse -->
	</div>
</nav>
<!-- Header -->
<div class="jumbotron">

	<div class="container">
		<h1>Filter dropdown</h1>
		<h2>How to create a custom dropdown filter for your table.</h2>
	</div>

</div>
<!-- Content -->
<div class="container">
	<div class="docs-section">

		<div class="callout callout-info">
			<h4>Notes</h4>
			<ul>
				<li>
					The base table in the example below is a clone of the <a href="../component/showcase.html">showcase example</a> to demonstrate that the dropdown keeps the filter state across
					various table operations such as filtering, sorting, paging.
				</li>
				<li>
					If you are upgrading to version 3.1.0 or higher from a 3.0.x version please pay special attention to <a href="#step-6">step 6</a> as the method to register the
					custom component has changed.
				</li>
			</ul>
		</div>

		<div class="example">
			<table id="filter-dropdown-example" class="table" data-paging="true" data-filtering="true" data-sorting="true"></table>
		</div>

		<h3>Step 1: Inheriting from the base filtering component</h3>
		<p>
			All core objects or "classes" in FooTable are derived from the <a href="../../jsdocs/FooTable.Class.html">FooTable.Class</a> object. This object exposes a single
			method called <code>extend</code> which allows you to create a whole new class from a base class (inherit) or to simply override a single method on an existing class.
			In this example we will be inheriting the base <a href="../../jsdocs/FooTable.Filtering.html">FooTable.Filtering</a> component, modifying it and then replacing it
			with our modified version.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>FooTable.MyFiltering = FooTable.Filtering.extend({ // inherit the base class
	construct: function(instance){ // override the default constructor
		this._super(instance); // call the base constructor
	}
});</code></pre>

		<h3>Step 2: Add custom properties for the dropdown</h3>
		<p>
			To make the code more maintainable going forward and easier to understand we will add some properties to our custom filtering component to hold the available options,
			the default option, and the jQuery wrapper around our dropdown.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>FooTable.MyFiltering = FooTable.Filtering.extend({
	construct: function(instance){
		this._super(instance);
		this.statuses = [&#39;Active&#39;,&#39;Disabled&#39;,&#39;Suspended&#39;]; // the options available in the dropdown
		this.def = &#39;Any Status&#39;; // the default/unselected value for the dropdown (this would clear the filter when selected)
		this.$status = null; // a placeholder for our jQuery wrapper around the dropdown
	}
});</code></pre>

		<h3>Step 3: Create the dropdown and append it to the table</h3>
		<p>
			To create the actual dropdown element and append it to the table we will override the <code>$create</code> method and generate our markup as required. The base filtering
			component exposes the property <code>$form</code> which is the jQuery wrapper for the form that contains the default search input. Using this we can simply create our
			dropdown and append it as required.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>$create: function(){
	this._super(); // call the base $create method, this populates the $form property
	var self = this, // hold a reference to my self for use later
		// create the bootstrap form group and append it to the form
		$form_grp = $(&#39;&lt;div/&gt;&#39;, {&#39;class&#39;: &#39;form-group&#39;})
			.append($(&#39;&lt;label/&gt;&#39;, {&#39;class&#39;: &#39;sr-only&#39;, text: &#39;Status&#39;}))
			.prependTo(self.$form);

	// create the select element with the default value and append it to the form group
	self.$status = $(&#39;&lt;select/&gt;&#39;, { &#39;class&#39;: &#39;form-control&#39; })
		.on(&#39;change&#39;, {self: self}, self._onStatusDropdownChanged)
		.append($(&#39;&lt;option/&gt;&#39;, {text: self.def}))
		.appendTo($form_grp);

	// add each of the statuses to the dropdown element
	$.each(self.statuses, function(i, status){
		self.$status.append($(&#39;&lt;option/&gt;&#39;).text(status));
	});
}</code></pre>

		<h3>Step 4: Handing the dropdown change event</h3>
		<p>
			At this point we have the dropdown appearing next to the search input but we still need to handle the change event we bound to above and actually apply the filter. To do
			this we will use the <code>addFilter</code>, <code>removeFilter</code> and <code>filter</code> methods.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>_onStatusDropdownChanged: function(e){
	var self = e.data.self, // get the MyFiltering object
		selected = $(this).val(); // get the current dropdown value
	if (selected !== self.def){ // if it's not the default value add a new filter
		self.addFilter('status', selected, ['status']);
	} else { // otherwise remove the filter
		self.removeFilter('status');
	}
	// initiate the actual filter operation
	self.filter();
}</code></pre>

		<h3>Step 5: Hooking into the draw operation</h3>
		<p>
			So now we have the dropdown, the filter is being added or removed in the change event as required but we also need the dropdown to be able to handle having it's value set
			through the options. To do this we hook into the <code>draw</code> method and check for the 'status' filter and if one exists update the dropdown as required.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>draw: function(){
	this._super(); // call the base draw method, this will handle the default search input
	var status = this.find(&#39;status&#39;); // find the status filter
	if (status instanceof FooTable.Filter){ // if it exists update the dropdown to reflect the value
		this.$status.val(status.query.val());
	} else { // otherwise update the dropdown to the default value
		this.$status.val(this.def);
	}
}</code></pre>

		<h3 id="step-6">Step 6: Global or instance specific</h3>
		<p>
			The final step is to simply decide whether the custom filtering should be applied to all tables in the page or just those specified by you. To register your custom filtering
			component for all tables in the page you need to use the <code>FooTable.components.register()</code> method as seen below.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>FooTable.components.register(&#39;filtering&#39;, FooTable.MyFiltering);</code></pre>
		<p>
			If you want to use your custom filtering component for only a single table or specific tables in a multi-table page then you need to make use of the
			<a href="../../getting-started.html#components">components</a> option. To do this you would provide the option as below when initializing the plugin.
		</p>
		<pre class="language-javascript between" data-lang="javascript"><code>$(&#39;.table&#39;).footable({
	components: {
		filtering: FooTable.MyFiltering
	}
});</code></pre>

		<h3>Finished!</h3>
		<p>That's it! We now have a custom filter dropdown that is fully integrated with the rest of the filter functionality. The full code can be seen below.</p>
		<pre class="language-javascript between" data-lang="javascript"><code>FooTable.MyFiltering = FooTable.Filtering.extend({
	construct: function(instance){
		this._super(instance);
		this.statuses = [&#39;Active&#39;,&#39;Disabled&#39;,&#39;Suspended&#39;];
		this.def = &#39;Any Status&#39;;
		this.$status = null;
	},
	$create: function(){
		this._super();
		var self = this,
			$form_grp = $(&#39;&lt;div/&gt;&#39;, {&#39;class&#39;: &#39;form-group&#39;})
				.append($(&#39;&lt;label/&gt;&#39;, {&#39;class&#39;: &#39;sr-only&#39;, text: &#39;Status&#39;}))
				.prependTo(self.$form);

		self.$status = $(&#39;&lt;select/&gt;&#39;, { &#39;class&#39;: &#39;form-control&#39; })
			.on(&#39;change&#39;, {self: self}, self._onStatusDropdownChanged)
			.append($(&#39;&lt;option/&gt;&#39;, {text: self.def}))
			.appendTo($form_grp);

		$.each(self.statuses, function(i, status){
			self.$status.append($(&#39;&lt;option/&gt;&#39;).text(status));
		});
	},
	_onStatusDropdownChanged: function(e){
		var self = e.data.self,
			selected = $(this).val();
		if (selected !== self.def){
			self.addFilter(&#39;status&#39;, selected, [&#39;status&#39;]);
		} else {
			self.removeFilter(&#39;status&#39;);
		}
		self.filter();
	},
	draw: function(){
		this._super();
		var status = this.find(&#39;status&#39;);
		if (status instanceof FooTable.Filter){
			this.$status.val(status.query.val());
		} else {
			this.$status.val(this.def);
		}
	}
});</code></pre>

		<p>Followed by either the below to register the component globally for all tables.</p>
		<pre class="language-javascript between" data-lang="javascript"><code>FooTable.components.register(&#39;filtering&#39;, FooTable.MyFiltering);</code></pre>
		<p>Or the below to register it for just a single table.</p>
		<pre class="language-javascript between" data-lang="javascript"><code>$(&#39;.table&#39;).footable({
	components: {
		filtering: FooTable.MyFiltering
	}
});</code></pre>


	</div>

</div> <!-- /container -->

<!-- Placed at the end of the document so the pages load faster -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="../../js/prism.js"></script>
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<script src="../../js/ie10-viewport-bug-workaround.js"></script>
<!-- Add in any FooTable dependencies we may need -->
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment.min.js"></script>
<!-- Add in FooTable itself -->
<script src="../../../compiled/footable.js"></script>
<!-- Initialize FooTable -->
<script>
FooTable.MyFiltering = FooTable.Filtering.extend({
	construct: function(instance){
		this._super(instance);
		this.statuses = ['Active','Disabled','Suspended'];
		this.def = 'Any Status';
		this.$status = null;
	},
	$create: function(){
		this._super();
		var self = this,
			$form_grp = $('<div/>', {'class': 'form-group'})
				.append($('<label/>', {'class': 'sr-only', text: 'Status'}))
				.prependTo(self.$form);

		self.$status = $('<select/>', { 'class': 'form-control' })
			.on('change', {self: self}, self._onStatusDropdownChanged)
			.append($('<option/>', {text: self.def}))
			.appendTo($form_grp);

		$.each(self.statuses, function(i, status){
			self.$status.append($('<option/>').text(status));
		});
	},
	_onStatusDropdownChanged: function(e){
		var self = e.data.self,
			selected = $(this).val();
		if (selected !== self.def){
			self.addFilter('status', selected, ['status']);
		} else {
			self.removeFilter('status');
		}
		self.filter();
	},
	draw: function(){
		this._super();
		var status = this.find('status');
		if (status instanceof FooTable.Filter){
			this.$status.val(status.query.val());
		} else {
			this.$status.val(this.def);
		}
	}
});

FooTable.components.register('filtering', FooTable.MyFiltering);

	jQuery(function($){
		$('#filter-dropdown-example').footable({
			"columns": $.get("../../content/columns.json"),
			"rows": $.get("../../content/rows.json")
		});
	});
</script>
</body>
</html>